import numpy as np


def active_fun(val):
    '''
    激活函数（sgn跃阶函数）
    :param val:
    :return:
    '''
    return 1.0 if val >= 0 else 0.0


class Perceptron:
    '''
    实现简单感知机
    '''

    def __init__(self, x_arr):
        '''
        :param x_arr: 各个输入特征，格式为
        [
           [x0（-1）,x1,x2,y],
           [x0（-1）,x1,x2,y],
           [x0（-1）,x1,x2,y]
        ]
        每组前三个数字为特征值，最后一个为目标值，另外，x1作为theta值，因此输入时，x1位置应固定输入-1
        '''
        # 转换为numpy数组
        self.inputs = np.array(x_arr)
        # 定义权重，这里取随机值,最后减一，因为数据集虽然有四列，但最后一列是目标值，因此刨除
        self.weights = np.random.rand(self.inputs.shape[1] - 1)

    def predict(self, x):
        '''
        预测函数
        :param x:输入一组特征，格式为[x1,x2,x3]
        :return: 返回预测结果，此处为
        '''
        np_x = np.array(x)
        # 矩阵相乘，并将结果矩阵的每个元素相加求和，求和结果计算激活函数后返回
        return active_fun(np.sum(np_x * self.weights))

    def train(self, rate, iteration):
        '''
        训练函数
        :param rate: 学习率
        :param iteration: 训练轮数
        :return: None
        '''
        for i in range(iteration):
            for idx in range(len(self.inputs)):
                # 获取目标值
                target = self.inputs[idx][-1]
                # 计算实际值
                actual = self.predict(self.inputs[idx][0:3])
                # 计算误差值
                err = target - actual
                print('目标值：',target)
                print('实际值：',actual)
                print('误差值：',err)
                # 计算delta_weight,并更新每个权重值
                # delta_weight公式：delta_weight=rate*error*xi
                for x_idx in range(len(self.weights)):
                    self.weights[x_idx] += rate * err * self.inputs[idx][x_idx]

    def __str__(self):
        return str(self.weights)

if __name__ == '__main__':
    # print(Perceptron([1.0,2.0]))
    datasets = [
        [-1, 1, 1, 1],
        [-1, 1, 0, 1],
        [-1, 0, 1, 1],
        [-1, 0, 0, 0]
    ]
    p = Perceptron(datasets)
    print('原始权重：',p)
    p.train(0.1, 10)
    print('最终权重：',p)
    # 测试，第一列需要设置为-1，以对应theta值
    print(p.predict([-1, 1, 1]))
    print(p.predict([-1, 0, 1]))
    print(p.predict([-1, 0, 0]))
    print(p.predict([-1, 1, 0]))
